#pragma once

#include <QAbstractTableModel>

struct TableRowItem
{
public:
    enum Type {
        Id = 0,
        Name,
        Grade,
        Progress,
        Checked,
        Path,
        TypeNum
    };
    int id;
    QString name;
    int grade;
    int progress;
    bool checked;
    QString path;

    static QStringList gradeNames() {
        static QStringList gradeNames =
            QStringList() << "Grade 1" << "Grade 2" << "Grade 3" << "Grade 4" << "Grade 5" << "Grade 6";
        return gradeNames;
    }

    static QStringList horizonalHeaderNames() {
        static QStringList horizonalHeaderNames =
            QStringList() << "ID"<<"Name"<<"Grade"<<"Progress"<<"Checked"<<"Path";
        return horizonalHeaderNames;
    }

    QVariant get(int index, int role = Qt::DisplayRole) const {
        switch (index) {
        case Id:
            return id;
        case Name:
            return name;
        case Grade:
            if(grade >= 0 && grade < gradeNames().size()) {
                if(role == Qt::EditRole)
                    return grade;
                return gradeNames().at(grade);
            }
        case Progress:
            return progress;
        case Checked:
            return checked;
        case Path:
            return path;
        default:
            break;
        }
        return QVariant();
    }

    bool set(int index, const QVariant &value, int role = Qt::EditRole) {
        switch (index) {
        case Id:
            if(value.type() == QVariant::Int) {
                id = value.toInt();
                return true;
            }
            break;
        case Name:
            if(value.type() == QVariant::String) {
                name = value.toString();
                return true;
            }
            break;
        case Grade:
            if(value.type() == QVariant::Int) {
                int _grade = value.toInt();
                if(_grade != grade && _grade >= 0 && _grade <= 5) {
                    grade = _grade;
                    return true;
                }
            }
            break;
        case Progress:
            if(value.type() == QVariant::Int) {
                int _progress = value.toInt();
                if(_progress != progress && _progress >= 0 && _progress <= 100) {
                    progress = _progress;
                    return true;
                }
            }
            break;
        case Checked:
            if(value.type() == QVariant::Bool) {
                checked = value.toBool();
                return true;
            }
            break;
        case Path:
            if(value.type() == QVariant::String) {
                path = value.toString();
                return true;
            }
            break;
        default:
            break;
        }
        return false;
    }
};

typedef QList<TableRowItem *> TableData;

class TableModel : public QAbstractTableModel
{
    Q_OBJECT

public:
    explicit TableModel(QObject *parent = nullptr);
    ~TableModel();

    // Header:
    QVariant headerData(int section,
                        Qt::Orientation orientation,
                        int role = Qt::DisplayRole) const override;

    bool setHeaderData(int section,
                       Qt::Orientation orientation,
                       const QVariant &value,
                       int role = Qt::EditRole) override;

    // Basic functionality:
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;

    // Fetch data dynamically:
    bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;

    bool canFetchMore(const QModelIndex &parent) const override;
    void fetchMore(const QModelIndex &parent) override;

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    // Editable:
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    Qt::ItemFlags flags(const QModelIndex &index) const override;

    // Add data:
    bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;

    // Remove data:
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;

    QStringList horizontalHeaders() const;
    void setHorizontalHeaders(const QStringList &newHorizontalHeaders);

    QStringList verticalHeaders() const;
    void setVerticalHeaders(const QStringList &newVerticalHeaders);

    bool appendRow(const TableRowItem &item);
    void clear();
private:
    QStringList m_horizontalHeaders;
    QStringList m_verticalHeaders;

    TableData m_data;
};
